import json
import sys
import os

class FileGenerator:
    def __init__(self, file_name, cpp_json, pb_json = None):
        self.file_name = file_name
        self.file_name_split = file_name.split(".")
        self.cpp_json = cpp_json
        self.pb_jsoon = pb_json
        self.gen_struct()
        self.gen_service_api()
        self.gen_service_impl()
        self.gen_service_proxy_api()
        self.gen_service_proxy_impl()
        self.gen_service_proxy_serializer_api()
        self.gen_service_stub_serializer_api()
        self.gen_service_stub_api()
        self.gen_service_stub_impl()
        self.gen_dynamic_service()
        
    def gen_dynamic_service(self):
        dynamic_service_list_file = open(self.file_name_split[0] + ".service.list", "w")
        for service in self.cpp_json["services"]:
            if service["loadType"] == "static":
                continue
            dynamic_service_list_file.write(service["uuid"] + " lib" + service["name"] + ".so\n")
            file = open(self.file_name_split[0] + ".service." + service["name"] +".so.h", "w")
            file.write("// Machine generated code\n\n")
            file.write("#pragma once\n\n")
            file.write("#if !defined(__linux__)\n")
            file.write('#    define FuncExport extern "C" __declspec(dllexport) // WIN32 DLL exporter\n')
            file.write("#else\n")
            file.write('#    define FuncExport extern "C" // LINUX shared object exporter\n')
            file.write('#endif // !defined(__linux__)\n')
            file.write('\n')
            file.write('#include <cstdint>\n')
            file.write('#include "rpc_service.h"\n')
            file.write('#include "rpc_logger.h"\n\n')
            file.write('FuncExport std::uint64_t onRegister(rpc::Logger* logger);\n')
            file.write("FuncExport rpc::RpcService* create();\n")
            file.write("FuncExport const char* onVersion();\n")
            file.write("FuncExport bool onBuildType();\n")
            file.write('extern rpc::Logger* getLogger();\n\n')
            file.write('#ifdef Logbegin\n')
            file.write('#undef Logbegin\n')
            file.write('#define Logbegin (rpc::LogWriter(getLogger()))\n')
            file.write('#endif\n\n')
            file.close()
        dynamic_service_list_file.close()            
        for service in self.cpp_json["services"]:
            if service["loadType"] == "static":
                continue
            file = open(self.file_name_split[0] + ".service." + service["name"] +".so.cpp", "w")
            file.write("// Machine generated code\n\n")
            file.write('#include "' + self.file_name_split[0] + ".service." + service["name"] + '.stub.h"\n')
            file.write('#include "' + self.file_name_split[0] + ".service." + service["name"] + '.impl.h"\n')
            file.write('#include "' + self.file_name_split[0] + ".service." + service["name"] + '.so.h"\n\n')
            file.write('rpc::Logger* logger_;\n\n')
            file.write('std::uint64_t onRegister(rpc::Logger* logger) {\n')
            file.write('    logger_ = logger;\n')
            file.write('    return ' + str(service["uuid"]) + ";\n")
            file.write('}\n\n')
            file.write("rpc::RpcService* create() {\n")
            file.write("    return new " + service["name"] + "Impl();\n")
            file.write("}\n\n")
            file.write("const char* onVersion() {\n")
            file.write('    static const char* version = "";\n')
            file.write("    return version;\n")
            file.write("}\n\n")
            file.write('bool onBuildType() {\n')
            file.write('    #if defined(_DEBUG) || defined(DEBUG)\n')
            file.write('        return true;\n')
            file.write('    #else\n')
            file.write('        return false;\n')
            file.write('    #endif\n')
            file.write('}\n\n')
            file.close()
        
    def gen_struct(self):
        file = open(self.file_name_split[0] + ".struct.h", "w")
        file.write("// Machine generated code\n\n")
        file.write("#pragma once\n\n")
        file.write("#include <string>\n")
        file.write("#include <cstdint>\n")
        file.write("#include <unordered_map>\n")
        file.write("#include <unordered_set>\n")
        file.write("#include <vector>\n")
        file.write("\n")
        file.write("namespace " + self.file_name_split[0] + "_cpp {\n\n")
        for name in self.cpp_json["structNames"]:
            file.write("struct " + name + ";\n")
        file.write("\n")
        for struct in self.cpp_json["structs"]:
            file.write("struct " + struct["name"] + " {\n")
            for field in struct["fields"]:
                if field["IdlType"] == "seq" or field["IdlType"] == "set":
                    file.write("    " + field["type"] + "<" + field["key"]["type"] + "> " + field["name"] + ";\n")
                elif field["IdlType"] == "dict":
                    file.write("    " + field["type"] + "<" + field["key"]["type"] + "," + field["value"]["type"] + "> " + field["name"] + ";\n")
                else:
                    file.write("    " + field["type"] + " " + field["name"] + ";\n")
            file.write("};\n\n")
        file.write("}\n\n")
        file.close()
        
    def gen_service_api(self):
        for service in self.cpp_json["services"]:
            service_file_header = ""
            service_interface_src = ""
            service_file_header += "// Machine generated code\n\n"
            service_file_header += "#pragma once\n\n"
            service_file_header += "#include <string>\n"
            service_file_header += "#include <cstdint>\n"
            service_file_header += "#include <unordered_map>\n"
            service_file_header += "#include <unordered_set>\n"
            service_file_header += "#include <vector>\n"
            service_file_header += "#include <memory>\n"
            service_file_header += "#include <functional>\n"
            service_file_header += '#include "rpc_stub.h"\n'
            service_file_header += '#include "rpc_service.h"\n'
            service_file_header += '#include "' + self.file_name_split[0] + '.struct.h"\n'
            service_file_header += "\n"
            service_file_header += "using namespace " + self.file_name_split[0] + "_cpp;\n\n"
            service_file_header += "class " + service["name"] + " : public rpc::RpcService {\n"
            service_file_header += "public:\n"
            service_interface_src += "    virtual ~" + service["name"] + "() {}\n"
            if (service["type"] != 'generic') and (service["methods"] is not None):
                for method in service["methods"]:
                    service_interface_src += "    " + "virtual "                
                    if method["retType"]["IdlType"] == "seq" or method["retType"]["IdlType"] == "set":
                        service_interface_src += "std::shared_ptr<" + method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + ">> "
                    elif method["retType"]["IdlType"] == "dict":
                        service_interface_src += "std::shared_ptr<" + method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + "," + method["retType"]["value"]["type"] + ">> "
                    elif method["retType"]["IdlType"] == "string" or method["retType"]["IdlType"] == "struct":
                        service_interface_src += "std::shared_ptr<" + method["retType"]["type"] + "> "
                    else:
                        service_interface_src += method["retType"]["type"] + " "
                    service_interface_src += method["name"] + "(rpc::StubCallPtr call"
                    n = 0
                    for arg in method["arguments"]:
                        if arg["IdlType"] == "void":
                            break;
                        n += 1
                        if arg["IdlType"] == "seq" or arg["IdlType"] == "set":
                            service_interface_src += ", const " + arg["type"] + "<" + arg["key"]["type"] + ">&"
                        elif arg["IdlType"] == "dict":
                            service_interface_src += ", const " + arg["type"] + "<" + arg["key"]["type"] + "," + arg["value"]["type"] + ">&"
                        elif arg["IdlType"] == "struct" or arg["IdlType"] == "string":
                            service_interface_src += ", const " + arg["type"] + "&"
                        else:
                            service_interface_src += ", " + arg["type"]
                    service_interface_src += ") = 0;\n"
            service_impl_header = ""
            service_impl_src = ""
            service_impl_header += "class " + service["name"] + "Impl : public " + service["name"] + " {\n"
            service_impl_header += "public:\n"
            service_impl_src += "    " + service["name"] + "Impl();\n"
            service_impl_src += "    virtual ~" + service["name"] + "Impl();\n"
            service_impl_src += "    virtual bool onAfterFork(rpc::Rpc* rpc) override;\n"
            service_impl_src += "    virtual bool onBeforeDestory(rpc::Rpc* rpc) override;\n"
            service_impl_src += "    virtual void onTick(std::time_t ms) override;\n"
            service_impl_src += "    virtual void onServiceCall(rpc::StubCallPtr callPtr) override;\n"
            if (service["type"] != 'generic') and (service["methods"] is not None):
                for method in service["methods"]:
                    service_impl_src += "    " + "virtual "
                    if method["retType"]["IdlType"] == "seq" or method["retType"]["IdlType"] == "set":
                        service_impl_src +=  "std::shared_ptr<" + method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + ">> "   
                    elif method["retType"]["IdlType"] == "dict":
                        service_impl_src += "std::shared_ptr<" + method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + "," + method["retType"]["value"]["type"] + ">> "                 
                    elif method["retType"]["IdlType"] == "string" or method["retType"]["IdlType"] == "struct":
                        service_impl_src += "std::shared_ptr<" + method["retType"]["type"] + "> "
                    else:
                        service_impl_src += method["retType"]["type"] + " "
                    service_impl_src += method["name"] + "(rpc::StubCallPtr call"
                    n = 0
                    for arg in method["arguments"]:
                        if arg["IdlType"] == "void":
                            break;
                        n += 1
                        if arg["IdlType"] == "seq" or arg["IdlType"] == "set":
                            service_impl_src += ", const " + arg["type"] + "<" + arg["key"]["type"] + ">&"
                        elif arg["IdlType"] == "dict":
                            service_impl_src += ", const " + arg["type"] + "<" + arg["key"]["type"] + "," + arg["value"]["type"] + ">&"
                        elif arg["IdlType"] == "struct" or arg["IdlType"] == "string":
                            service_impl_src += ", const " + arg["type"] + "&"
                        else:
                            service_impl_src += ", " + arg["type"]
                    service_impl_src += ") override;\n"
            interface_file_name = self.file_name_split[0] + ".service." + service["name"] +".h"
            file = open(interface_file_name, "w")                
            file.write(service_file_header)
            file.write("//interface->\n")
            file.write(service_interface_src)
            file.write("//interface<-\n")
            file.write("};\n\n")
            file.close()
            impl_file_name = self.file_name_split[0] + ".service." + service["name"] +".impl.h"
            if not os.path.exists(impl_file_name):
                file_impl = open(impl_file_name, "w")
                file_impl.write("#pragma once\n\n")
                file_impl.write('#include "' + interface_file_name + '"\n\n')
                file_impl.write(service_impl_header)
                file_impl.write("//implementation->\n")
                file_impl.write(service_impl_src)
                file_impl.write("//implementation<-\n")
                file_impl.write("};\n\n")
                file_impl.close()
            
    # TODO update impl file content
    def gen_service_impl(self):
        for service in self.cpp_json["services"]:
            file = open(self.file_name_split[0] + ".service." + service["name"] +".cpp", "w")
            file.write("// Machine generated code\n\n")
            file.write('#include <utility>\n')
            file.write('#include "rpc_singleton.h"\n')
            file.write('#include "object_pool.h"\n')
            file.write('#include "' + self.file_name_split[0] + ".service." + service["name"] +'.impl.h"\n\n')
            file.write(service["name"] + "Impl::" + service["name"] + "Impl() {}\n")
            file.write(service["name"] + "Impl::~" + service["name"] + "Impl() {}\n")
            file.write("bool " + service["name"] + "Impl::" + "onAfterFork(rpc::Rpc* rpc) { return true; }\n")
            file.write("bool " + service["name"] + "Impl::" + "onBeforeDestory(rpc::Rpc* rpc) { return true; }\n")
            file.write("void " + service["name"] + "Impl::" + "onTick(std::time_t ms) { return; }\n")
            file.write("void " + service["name"] + "Impl::" + "onServiceCall(rpc::StubCallPtr callPtr) { return; }\n")
            if (service["type"] != 'generic') and (service["methods"] is not None):
                for method in service["methods"]:
                    retTypeStr = ""
                    isPtr = False
                    if method["retType"]["IdlType"] == "seq" or method["retType"]["IdlType"] == "set":
                        file.write("std::shared_ptr<")
                        retTypeStr = method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + ">"
                        file.write(method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + ">")
                        file.write("> ")
                        isPtr = True
                    elif method["retType"]["IdlType"] == "dict":
                        file.write("std::shared_ptr<")
                        retTypeStr = method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + "," + method["retType"]["value"]["type"] + ">"
                        file.write(method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + "," + method["retType"]["value"]["type"] + ">")
                        file.write("> ")
                        isPtr = True
                    elif method["retType"]["IdlType"] == "string" or method["retType"]["IdlType"] == "struct":
                        file.write("std::shared_ptr<")
                        retTypeStr = method["retType"]["type"]
                        file.write(method["retType"]["type"])
                        file.write("> ")
                        isPtr = True
                    else:
                        file.write(method["retType"]["type"] + " ")
                        retTypeStr = method["retType"]["type"]
                    file.write(service["name"] + "Impl::" + method["name"] + "(rpc::StubCallPtr call")
                    n = 0
                    for arg in method["arguments"]:
                        if arg["IdlType"] == "void":
                            break;
                        n += 1
                        if arg["IdlType"] == "seq" or arg["IdlType"] == "set":
                            file.write(", const " + arg["type"] + "<" + arg["key"]["type"] + ">&")
                        elif arg["IdlType"] == "dict":
                            file.write(", const " + arg["type"] + "<" + arg["key"]["type"] + "," + arg["value"]["type"] + ">&")
                        elif arg["IdlType"] == "struct" or arg["IdlType"] == "string":
                            file.write(", const " + arg["type"] + "&")
                        else:
                            file.write(", " + arg["type"])
                    file.write(") {\n")
                    if not method["retType"]["IdlType"] == "void":
                        if isPtr:
                            file.write("    return rpc::make_return<" + retTypeStr + ">(call);\n")
                        else:
                            if method["retType"]["IdlType"] == "bool":
                                file.write("    return false;\n")
                            else:
                                file.write("    return 0;\n")
                    file.write("}\n\n")
                file.close()
            
    def gen_service_proxy_api(self):
        for service in self.cpp_json["services"]:
            file = open(self.file_name_split[0] + ".service." + service["name"] +".proxy.h", "w")
            file.write("// Machine generated code\n\n")
            file.write("#pragma once\n\n")
            file.write("#include <string>\n");
            file.write("#include <cstdint>\n");
            file.write("#include <unordered_map>\n");
            file.write("#include <unordered_set>\n");
            file.write("#include <vector>\n");
            file.write("#include <memory>\n");
            file.write("#include <functional>\n");
            file.write('#include "rpc_proxy.h"\n')
            file.write('#include "' + self.file_name_split[0] + '.struct.h"\n')
            file.write("\n")
            file.write("using namespace " + self.file_name_split[0] + "_cpp;\n\n")
            if service["methods"] is not None:
                for method in service["methods"]:
                    if not "oneway" in method:
                        file.write("using " + service["name"] + "_" + method["name"] + "_callback = std::function<void(")
                        if method["retType"]["IdlType"] == "seq" or method["retType"]["IdlType"] == "set":
                            file.write("const " + method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + ">&,")
                        elif method["retType"]["IdlType"] == "dict":
                            file.write("const " + method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + "," + method["retType"]["value"]["type"] + ">&,")
                        elif method["retType"]["IdlType"] == "struct" or method["retType"]["IdlType"] == "string":
                            file.write("const " + method["retType"]["type"] + "&,")
                        else:
                            if method["retType"]["IdlType"] != "void":
                                file.write(method["retType"]["type"] + ",")
                        file.write("rpc::RpcError)>;\n")
            file.write("\n")
            file.write("class " + service["name"] + "Proxy : public virtual rpc::Proxy {\n")
            file.write("public:\n")
            file.write("    virtual ~" + service["name"] + "Proxy() {}\n")
            file.write("    static std::uint64_t uuid() { return std::uint64_t(" + service["uuid"] + "); }\n") 
            if service["methods"] is not None:
                for method in service["methods"]:
                    file.write("    virtual ")
                    if method["retType"]["IdlType"] == "seq" or method["retType"]["IdlType"] == "set":
                        file.write("std::shared_ptr<")
                        file.write(method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + ">")
                        file.write("> ")
                    elif method["retType"]["IdlType"] == "dict":
                        file.write("std::shared_ptr<")
                        file.write(method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + "," + method["retType"]["value"]["type"] + ">")
                        file.write("> ")
                    elif method["retType"]["IdlType"] == "struct":
                        file.write("std::shared_ptr<")
                        file.write(method["retType"]["type"])
                        file.write("> ")
                    else:
                        file.write(method["retType"]["type"] + " ")
                    file.write(method["name"] + "(")
                    n = 0
                    for arg in method["arguments"]:
                        n += 1
                        if arg["IdlType"] == "seq" or arg["IdlType"] == "set":
                            file.write("const " + arg["type"] + "<" + arg["key"]["type"] + ">&")
                        elif arg["IdlType"] == "dict":
                            file.write("const " + arg["type"] + "<" + arg["key"]["type"] + "," + arg["value"]["type"] + ">&")
                        elif arg["IdlType"] == "struct" or arg["IdlType"] == "string":
                            file.write("const " + arg["type"] + "&")
                        elif arg["IdlType"] == "void":
                            n -= 1
                            continue
                        else:
                            file.write(arg["type"])
                        if n + 1 <= len(method["arguments"]):
                            file.write(", ")
                    file.write(") = 0;\n")
            file.write("\n")
            if service["methods"] is not None:
                for method in service["methods"]:
                    if "oneway" in method:
                        continue
                    file.write("    virtual void ")
                    file.write(method["name"] + "(")
                    n = 0
                    for arg in method["arguments"]:
                        n += 1
                        if arg["IdlType"] == "seq" or arg["IdlType"] == "set":
                            file.write("const " + arg["type"] + "<" + arg["key"]["type"] + ">&,")
                        elif arg["IdlType"] == "dict":
                            file.write("const " + arg["type"] + "<" + arg["key"]["type"] + "," + arg["value"]["type"] + ">&,")
                        elif arg["IdlType"] == "struct" or arg["IdlType"] == "string":
                            file.write("const " + arg["type"] + "&,")
                        elif arg["IdlType"] == "void":
                            n -= 1
                            continue
                        else:
                            file.write(arg["type"] + ",")
                    file.write(service["name"] + "_" + method["name"] + "_callback")
                    file.write(") = 0;\n")
            file.write("};\n\n")
            file.write('using ' + service["name"] + 'Prx = std::shared_ptr<' + service["name"] + 'Proxy>;\n\n')
            file.close()

    def gen_service_stub_serializer_api(self):
        for service in self.cpp_json["services"]:
            file = open(self.file_name_split[0] + ".service." + service["name"] +".stub.serializer.h", "w")
            file.write("// Machine generated code\n\n")
            file.write("#pragma once\n\n")
            file.write('#include "' + self.file_name_split[0] + ".service." + service["name"] +'.stub.h"\n')
            file.write("\n")
            file.write("using namespace " + self.file_name_split[0] + "_cpp;\n\n")
            if (service["type"] != 'generic') and (service["methods"] is not None):
                for method in service["methods"]:
                    file.write("extern void deserialize_stub_" + service["name"] + "_" + method["name"] + "(rpc::StubCallPtr")
                    for arg in method["arguments"]:
                        if arg["IdlType"] == "void":
                            break;
                        if arg["IdlType"] == "seq" or arg["IdlType"] == "set":
                            file.write(", " + arg["type"] + "<" + arg["key"]["type"] + ">&")
                        elif arg["IdlType"] == "dict":
                            file.write(", " + arg["type"] + "<" + arg["key"]["type"] + "," + arg["value"]["type"] + ">&")
                        elif arg["IdlType"] == "struct" or arg["IdlType"] == "string":
                            file.write(", " + arg["type"] + "&")
                        else:
                            file.write(", " + arg["type"] + "&")
                    file.write(");\n")
            if (service["type"] != 'generic') and (service["methods"] is not None):
                for method in service["methods"]:
                    if "oneway" in method:
                        continue;
                    file.write("extern void serialize_stub_" + service["name"] + "_" + method["name"] + "_retval(rpc::StubCallPtr, const char* signature, rpc::ServiceID serviceID, rpc::ErrorID errorID")
                    if method["retType"]["IdlType"] == "seq" or method["retType"]["IdlType"] == "set":
                        file.write(", std::shared_ptr<")
                        file.write(method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + ">")
                        file.write(">")
                    elif method["retType"]["IdlType"] == "dict":
                        file.write(", std::shared_ptr<")
                        file.write(method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + "," + method["retType"]["value"]["type"] + ">")
                        file.write(">")
                    elif method["retType"]["IdlType"] == "struct" or method["retType"]["IdlType"] == "string":
                        file.write(", std::shared_ptr<")
                        file.write(method["retType"]["type"])
                        file.write(">")
                    elif method["retType"]["IdlType"] == "void":
                        pass
                    else:
                        file.write(", " + method["retType"]["type"] + " ")
                    file.write(");\n")

    def gen_service_proxy_serializer_api(self):
        for service in self.cpp_json["services"]:
            file = open(self.file_name_split[0] + ".service." + service["name"] +".proxy.serializer.h", "w")
            file.write("// Machine generated code\n\n")
            file.write("#pragma once\n\n")
            file.write('#include "' + self.file_name_split[0] + ".service." + service["name"] +'.proxy.h"\n')
            file.write("\n")
            file.write("using namespace " + self.file_name_split[0] + "_cpp;\n\n")
            if service["methods"] is not None:
                for method in service["methods"]:
                    file.write("extern void serialize_" + service["name"] + "_" + method["name"] + "(rpc::Proxy* proxy, rpc::ProxyCallPtr callPtr, rpc::MethodID methodID, rpc::TransportPtr transport")
                    for arg in method["arguments"]:
                        if arg["IdlType"] == "void":
                            break;
                        if arg["IdlType"] == "seq" or arg["IdlType"] == "set":
                            file.write(", const " + arg["type"] + "<" + arg["key"]["type"] + ">&")
                        elif arg["IdlType"] == "dict":
                            file.write(", const " + arg["type"] + "<" + arg["key"]["type"] + "," + arg["value"]["type"] + ">&")
                        elif arg["IdlType"] == "struct" or arg["IdlType"] == "string":
                            file.write(", const " + arg["type"] + "&")
                        else:
                            file.write(", " + arg["type"])
                    file.write(");\n")
            if service["methods"] is not None:
                for method in service["methods"]:
                    if "oneway" in method:
                        continue;
                    file.write("extern void deserialize_" + service["name"] + "_" + method["name"] + "(" + service["name"] + "_" + method["name"] + "_callback, rpc::TransportPtr, int, rpc::RpcError);\n");
                    file.write("extern ")
                    if method["retType"]["IdlType"] == "seq" or method["retType"]["IdlType"] == "set":
                        file.write("std::shared_ptr<")
                        file.write(method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + ">")
                        file.write("> ")
                    elif method["retType"]["IdlType"] == "dict":
                        file.write("std::shared_ptr<")
                        file.write(method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + "," + method["retType"]["value"]["type"] + ">")
                        file.write("> ")
                    elif method["retType"]["IdlType"] == "struct":
                        file.write("std::shared_ptr<")
                        file.write(method["retType"]["type"])
                        file.write("> ")
                    elif method["retType"]["IdlType"] == "void":
                        file.write("void ")
                    else:
                        file.write(method["retType"]["type"] + " ")
                    file.write("deserialize_" + service["name"] + "_" + method["name"] + "_coro(rpc::TransportPtr, int);\n")            
            
    def gen_service_proxy_impl(self):
        for service in self.cpp_json["services"]:
            file = open(self.file_name_split[0] + ".service." + service["name"] +".proxy.cpp", "w")
            file.write("// Machine generated code\n\n")
            file.write('#include "' + self.file_name_split[0] + ".service." + service["name"] + '.proxy.h"\n')
            file.write('#include "' + self.file_name_split[0] + ".service." + service["name"] + '.proxy.serializer.h"\n')
            file.write('#include "rpc_root.h"\n')
            file.write('#include "rpc_proxy.h"\n')
            file.write('#include "rpc_stub.h"\n\n')
            file.write("\n")
            file.write("class " + service["name"] + "ProxyImpl : public " + service["name"] + "Proxy, public rpc::ProxyImpl {\n")
            file.write("public:\n")
            file.write("    virtual ~" + service["name"] + "ProxyImpl() {}\n")
            file.write("    virtual const char* getSignature(rpc::MethodID methodID) const override;\n")
            file.write("    virtual rpc::ServiceUUID getServiceUUID() override { return " + "uuid(); }\n")
            file.write("    virtual bool isOneway(rpc::MethodID methodID) override;\n")
            if service["methods"] is not None:
                for method in service["methods"]:
                    file.write("    virtual ")
                    if method["retType"]["IdlType"] == "seq" or method["retType"]["IdlType"] == "set":
                        file.write("std::shared_ptr<")
                        file.write(method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + ">")
                        file.write("> ")
                    elif method["retType"]["IdlType"] == "dict":
                        file.write("std::shared_ptr<")
                        file.write(method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + "," + method["retType"]["value"]["type"] + ">")
                        file.write("> ")
                    elif method["retType"]["IdlType"] == "struct":
                        file.write("std::shared_ptr<")
                        file.write(method["retType"]["type"])
                        file.write("> ")
                    else:
                        file.write(method["retType"]["type"] + " ")
                    file.write(method["name"] + "(")
                    n = 0
                    for arg in method["arguments"]:
                        n += 1
                        if arg["IdlType"] == "seq" or arg["IdlType"] == "set":
                            file.write("const " + arg["type"] + "<" + arg["key"]["type"] + ">&")
                        elif arg["IdlType"] == "dict":
                            file.write("const " + arg["type"] + "<" + arg["key"]["type"] + "," + arg["value"]["type"] + ">&")
                        elif arg["IdlType"] == "struct" or arg["IdlType"] == "string":
                            file.write("const " + arg["type"] + "&")
                        elif arg["IdlType"] == "void":
                            n -= 1
                            continue
                        else:
                            file.write(arg["type"])
                        if n + 1 <= len(method["arguments"]):
                            file.write(", ")
                    file.write(") override;\n")
            file.write("\n")
            if service["methods"] is not None:
                for method in service["methods"]:
                    if "oneway" in method:
                        continue
                    file.write("    virtual void ")
                    file.write(method["name"] + "(")
                    n = 0
                    for arg in method["arguments"]:
                        n += 1
                        if arg["IdlType"] == "seq" or arg["IdlType"] == "set":
                            file.write("const " + arg["type"] + "<" + arg["key"]["type"] + ">&,")
                        elif arg["IdlType"] == "dict":
                            file.write("const " + arg["type"] + "<" + arg["key"]["type"] + "," + arg["value"]["type"] + ">&,")
                        elif arg["IdlType"] == "struct" or arg["IdlType"] == "string":
                            file.write("const " + arg["type"] + "&,")
                        elif arg["IdlType"] == "void":
                            n -= 1
                            continue
                        else:
                            file.write(arg["type"] + ",")
                    file.write(service["name"] + "_" + method["name"] + "_callback")
                    file.write(") override;\n")
            file.write("};\n\n")       
            file.write("bool __" + service["name"] + "_register__ = rpc::registerServiceFactory<" + service["name"] + "ProxyImpl>();\n\n")     
            file.write("const char* " + service["name"] + "ProxyImpl::getSignature(rpc::MethodID methodID) const {\n")
            file.write("    switch (methodID) {\n")
            n = 1
            if service["methods"] is not None:
                for method in service["methods"]:
                    file.write("        case " + str(n) + ":\n")
                    file.write('            return "' + service["name"] + "::" + method["name"] + '";\n')
                    n += 1
                file.write("        default:\n")
                file.write("            return nullptr;\n")
                file.write("    }\n")
                file.write("}\n\n")
                file.write("bool " + service["name"] + "ProxyImpl::isOneway(rpc::MethodID methodID) {\n")
                file.write("    switch (methodID) {\n")
            n = 1
            if service["methods"] is not None:
                for method in service["methods"]:
                    file.write("        case " + str(n) + ":\n")
                    if "oneway" in method:
                        file.write('            return true;\n')
                    else:
                        file.write('            return false;\n')
                    n += 1
            file.write("        default:\n")
            file.write("            return false;\n")
            file.write("    }\n")
            file.write("}\n\n")
            if service["methods"] is not None:
                for method in service["methods"]:
                    if "oneway" in method:
                        continue
                    file.write("class " + service["name"] + "_" + method["name"] + "_ProxyCall : public rpc::ProxyCall {\n")
                    file.write("    " + service["name"] + "_" + method["name"] + "_callback callback_;\n")
                    file.write("    coroutine::CoroID coroID_ {coroutine::INVALID_CORO_ID};\n")
                    file.write("    int byteSize_ {0};\n")
                    file.write("    rpc::ProxyID proxyID_ {0};\n")
                    file.write("public:\n")
                    file.write("    " + service["name"] + "_" + method["name"] + "_ProxyCall(rpc::Rpc* rpc, rpc::ProxyID proxyID, rpc::TransportPtr transport,")
                    file.write(service["name"] + "_" + method["name"] + "_callback callback = nullptr, coroutine::CoroID coroID = coroutine::INVALID_CORO_ID) {\n")
                    file.write("        callback_ = callback;\n")
                    file.write("        transport_ = transport;\n")
                    file.write("        coroID_ = coroID;\n")
                    file.write("        rpc_ = rpc;\n")
                    if method.has_key('retry'):
                        file.write("        setRetry(" + str(method["retry"]) + ");\n");
                    file.write("        proxyID_ = proxyID;\n")
                    if method.has_key("timeout"):
                        file.write("        setTimeout(" + str(method["timeout"]) + ");\n")
                    if method.has_key("retry"):
                        file.write("        setRetry(" + str(method["retry"]) + ");\n")
                    noexcept_flag = "true"
                    if not method["noexcept"]:
                        noexcept_flag = "false"
                    file.write("        setNoExcept(" + noexcept_flag + ");\n")
                    file.write("    #ifdef DEBUG\n")
                    file.write('        setCallName("' + service["name"] + "::" + method["name"] + '");\n')
                    file.write("    #endif\n")
                    file.write("    }\n\n")
                    file.write("    virtual ~" + service["name"] + "_" + method["name"] + "_ProxyCall() {\n")
                    file.write(     "}\n\n")
                    file.write("    virtual void doRet(int bytes) {\n")       
                    file.write("        if (coroID_ != coroutine::INVALID_CORO_ID) {\n")
                    file.write("            byteSize_ = bytes;\n")
                    file.write("            coro_resume(coroID_);\n")
                    file.write("            return;\n")
                    file.write("        } else {\n")
                    file.write("            if (callback_) {\n")
                    file.write("                deserialize_" + service["name"] + "_" + method["name"] + "(callback_, transport_, bytes, static_cast<rpc::RpcError>(getErrorID()));\n")
                    file.write("            }\n")
                    file.write("            rpc_->getProxyCallManager()->destroy(getCallID());\n")
                    file.write("        }\n")
                    file.write("    }\n\n")
                    file.write("    virtual rpc::ProxyID getProxyID() { return proxyID_; }\n\n")
                    file.write("    ")
                    if method["retType"]["IdlType"] == "seq" or method["retType"]["IdlType"] == "set":
                        file.write("std::shared_ptr<")
                        file.write(method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + ">")
                        file.write("> ")
                    elif method["retType"]["IdlType"] == "dict":
                        file.write("std::shared_ptr<")
                        file.write(method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + "," + method["retType"]["value"]["type"] + ">")
                        file.write("> ")
                    elif method["retType"]["IdlType"] == "struct":
                        file.write("std::shared_ptr<")
                        file.write(method["retType"]["type"])
                        file.write("> ")
                    else:
                        file.write(method["retType"]["type"] + " ")
                    file.write("doCoroRet() {\n")
                    file.write("        return deserialize_" + service["name"] + "_" + method["name"] + "_coro(transport_, byteSize_);\n");
                    file.write("    }\n\n")
                    file.write("};\n\n")
            index = 0
            if service["methods"] is not None:
                for method in service["methods"]:
                    index += 1
                    if not "oneway" in method:
                        if method["retType"]["IdlType"] == "seq" or method["retType"]["IdlType"] == "set":
                            file.write("std::shared_ptr<")
                            file.write(method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + ">")
                            file.write("> ")
                        elif method["retType"]["IdlType"] == "dict":
                            file.write("std::shared_ptr<")
                            file.write(method["retType"]["type"] + "<" + method["retType"]["key"]["type"] + "," + method["retType"]["value"]["type"] + ">")
                            file.write("> ")
                        elif method["retType"]["IdlType"] == "struct":
                            file.write("std::shared_ptr<")
                            file.write(method["retType"]["type"])
                            file.write("> ")
                        elif method["retType"]["IdlType"] == "void":
                            file.write("void ")
                        else:
                            file.write(method["retType"]["type"] + " ")
                    else:
                        file.write("void ")
                    file.write(service["name"] + "ProxyImpl" + "::" + method["name"] + "(")
                    for arg in method["arguments"]:
                        if arg["IdlType"] == "void":
                            break;
                        if arg["IdlType"] == "seq" or arg["IdlType"] == "set":
                            file.write("const " + arg["type"] + "<" + arg["key"]["type"] + ">&")
                        elif arg["IdlType"] == "dict":
                            file.write("const " + arg["type"] + "<" + arg["key"]["type"] + "," + arg["value"]["type"] + ">&")
                        elif arg["IdlType"] == "struct" or arg["IdlType"] == "string":
                            file.write("const " + arg["type"] + "&")
                        else:
                            file.write(arg["type"])
                        file.write(" _" + str(arg["index"]))
                        if arg["index"] < len(method["arguments"]):
                            file.write(", ")
                    file.write(") {\n")                
                    if "oneway" in method:
                        file.write("    serialize_" + service["name"] + "_" + method["name"] + "(this, nullptr, " + str(index) + ", getTransport()")
                        for arg in method["arguments"]:
                            if arg["IdlType"] == "void":
                                break;
                            file.write(", _" + str(arg["index"]))
                        file.write(");\n")
                    else:
                        file.write('    if (coro_is_main()) { throw rpc::ProxyCoroMethodException("Cannot call this method in main coroutine"); }\n')
                        file.write("    auto call = getRpc()->make_shared_ptr<" + service["name"] + "_" + method["name"] + "_ProxyCall>(getRpc(), getID(), getTransport(), nullptr, coro_id());\n")
                        file.write("    call->setCoro();\n")
                        file.write("    getRpc()->getProxyCallManager()->add(call);\n")
                        file.write("    serialize_" + service["name"] + "_" + method["name"] + "(this, call, " + str(index) + ", getTransport()")
                        for arg in method["arguments"]:
                            if arg["IdlType"] == "void":
                                break;
                            file.write(", _" + str(arg["index"]))
                        file.write(");\n")
                        file.write("    coro_yield();\n")
                        file.write("    while (call->needRetry()) {\n")
                        file.write("        if (static_cast<rpc::RpcError>(call->getErrorID()) == rpc::RpcError::TIMEOUT) {\n")
                        file.write("            getRpc()->getProxyCallManager()->retry(call);\n")
                        file.write("            coro_yield();\n")
                        file.write("        } else {\n")
                        file.write("            break;\n")
                        file.write("        }\n")
                        file.write("    }\n")
                        file.write("    auto errorID = static_cast<rpc::RpcError>(call->getErrorID());\n")
                        file.write("    if ((errorID != rpc::RpcError::OK) && (!call->getNoExcept())) {\n")
                        file.write("        getRpc()->getProxyCallManager()->destroy(call->getCallID());\n")
                        file.write("        switch (static_cast<rpc::RpcError>(errorID)) {\n")
                        file.write("            case rpc::RpcError::NOT_FOUND:\n")
                        file.write("                throw rpc::MethodNotFound(getSignature(" + str(method["index"]) + "));\n")
                        file.write("            case rpc::RpcError::EXCEPTION:\n")
                        file.write("                throw rpc::RemoteMethodException(getSignature(" + str(method["index"]) + "));\n")
                        file.write("            case rpc::RpcError::TIMEOUT:\n")
                        file.write("                throw rpc::RemoteMethodTimeout(getSignature(" + str(method["index"]) + "));\n")
                        file.write("            default: break;\n")
                        file.write("        }\n")
                        file.write("    }\n")
                        file.write("    getRpc()->getProxyCallManager()->destroy(call->getCallID());\n")
                        file.write("    return call->doCoroRet();\n")
                    file.write("}\n\n")
            index = 0
            if service["methods"] is not None:
                for method in service["methods"]:
                    index += 1
                    if "oneway" in method:
                        continue
                    file.write("void ")
                    file.write(service["name"] + "ProxyImpl::" + method["name"] + "(")
                    for arg in method["arguments"]:
                        if arg["IdlType"] == "seq" or arg["IdlType"] == "set":
                            file.write("const " + arg["type"] + "<" + arg["key"]["type"] + ">&")
                        elif arg["IdlType"] == "dict":
                            file.write("const " + arg["type"] + "<" + arg["key"]["type"] + "," + arg["value"]["type"] + ">&")
                        elif arg["IdlType"] == "struct" or arg["IdlType"] == "string":
                            file.write("const " + arg["type"] + "&")
                        elif arg["IdlType"] == "void":
                            break
                        else:
                            file.write(arg["type"])
                        file.write(" _" + str(arg["index"]) + ", ")
                    file.write(service["name"] + "_" + method["name"] + "_callback callback")
                    file.write(") {\n")
                    if "oneway" in method:
                        file.write("    serialize_" + service["name"] + "_" + method["name"] + "(this, call, " + str(index) + ", getTransport()")
                        for arg in method["arguments"]:
                            if arg["IdlType"] == "void":
                                break
                            file.write(", _" + str(arg["index"]))
                        file.write(");\n")
                    else:
                        file.write("    auto call = getRpc()->make_shared_ptr<" + service["name"] + "_" + method["name"] + "_ProxyCall>(getRpc(), getID(), getTransport(), callback);\n")
                        file.write("    getRpc()->getProxyCallManager()->add(call);\n")
                        file.write("    serialize_" + service["name"] + "_" + method["name"] + "(this, call, " + str(index) + ", getTransport()")
                        for arg in method["arguments"]:
                            if arg["IdlType"] == "void":
                                break
                            file.write(", _" + str(arg["index"]))
                        file.write(");\n")
                    file.write("}\n\n")

    def gen_service_stub_api(self):
        for service in self.cpp_json["services"]:
            file = open(self.file_name_split[0] + ".service." + service["name"] +".stub.h", "w")
            file.write("// Machine generated code\n\n")
            file.write("#pragma once\n\n")
            file.write('#include "' + self.file_name_split[0] + ".service." + service["name"] + '.h"\n')
            file.write('#include "rpc_defines.h"\n\n')
            file.write("class " + service["name"] + ";\n\n")
            file.write("using namespace " + self.file_name_split[0] + "_cpp;\n\n")
            file.write("class " + service["name"] + "Stub : public rpc::StubImpl {\n")
            file.write("    std::shared_ptr<" + service["name"] + "> service_;\n")
            file.write("public:\n")
            file.write("    " + service["name"] + "Stub();\n")
            file.write("    virtual ~" + service["name"] + "Stub() {}\n")
            file.write("    static std::uint64_t uuid() { return std::uint64_t(" + service["uuid"] + "); }\n")
            file.write("    virtual std::uint64_t getUUID() override { return uuid(); }\n")
            file.write('    virtual const char* getServiceName() override { return "' + service["name"] + '"; }\n')
            file.write("    virtual const char* getMethodName(rpc::MethodID method) override;\n")
            file.write("    virtual void call(rpc::StubCallPtr callPtr) override;\n")
            file.write("    virtual bool onAfterFork(rpc::Rpc* rpc) override;\n")
            file.write("    virtual bool onBeforeDestory(rpc::Rpc* rpc) override;\n")
            file.write("    virtual bool reset(rpc::BundleEntryFunc entryFunc, rpc::Rpc* rpc) override;\n")
            file.write("    virtual void tick(std::time_t ms) override;\n")
            file.write("\n")
            file.write("private:\n")
            if (service["type"] != 'generic') and (service["methods"] is not None):
                for method in service["methods"]:
                    file.write("    void " + method["name"] + "(rpc::StubCallPtr callPtr);\n");
            file.write("};\n\n")
            
    def gen_service_stub_impl(self):
        for service in self.cpp_json["services"]:
            file = open(self.file_name_split[0] + ".service." + service["name"] +".stub.cpp", "w")
            file.write("// Machine generated code\n\n")
            file.write('#include "' + self.file_name_split[0] + '.struct.h"\n')
            file.write('#include "' + self.file_name_split[0] + ".service." + service["name"] + '.stub.serializer.h"\n')
            file.write('#include "' + self.file_name_split[0] + ".service." + service["name"] + '.stub.h"\n\n')
            if service["loadType"] != "dynamic":
                file.write('#include "' + self.file_name_split[0] + ".service." + service["name"] + '.impl.h"\n\n')
            file.write('#include "rpc_root.h"\n')
            file.write('#include "rpc_proxy.h"\n')
            file.write('#include "rpc_stub.h"\n\n')
            if service["type"] == "single":
                if service["loadType"] == "dynamic":
                    file.write("bool __Stub" + service["name"] + "_register__ = StubCreatorRef.registerServiceFactory<" + service["name"] + "Stub, rpc::StubFactorySingleDynamicT<" + service["name"] + "Stub>>();\n\n")
                else:
                    file.write("bool __Stub" + service["name"] + "_register__ = StubCreatorRef.registerServiceFactory<" + service["name"] + "Stub, rpc::StubFactorySingleT<" + service["name"] + "Stub>>();\n\n")
            elif service["type"] == "multiple":
                if service.has_key("maxInst"):
                    if service["loadType"] == "dynamic":
                        file.write("bool __Stub" + service["name"] + "_register__ = StubCreatorRef.registerServiceFactory<" + service["name"] + "Stub, rpc::StubFactoryMultipleDynamicT<" + service["name"] + "Stub>>(" + str(service["maxInst"]) + ");\n\n")
                    else:
                        file.write("bool __Stub" + service["name"] + "_register__ = StubCreatorRef.registerServiceFactory<" + service["name"] + "Stub, rpc::StubFactoryMultipleT<" + service["name"] + "Stub>>(" + str(service["maxInst"]) + ");\n\n")
                else:
                    if service["loadType"] == "dynamic":
                        file.write("bool __Stub" + service["name"] + "_register__ = StubCreatorRef.registerServiceFactory<" + service["name"] + "Stub, rpc::StubFactoryMultipleDynamicT<" + service["name"] + "Stub>>();\n\n")
                    else:
                        file.write("bool __Stub" + service["name"] + "_register__ = StubCreatorRef.registerServiceFactory<" + service["name"] + "Stub, rpc::StubFactoryMultipleT<" + service["name"] + "Stub>>();\n\n")
            elif service["type"] == "generic" or service["type"] == "reentrant":
                if service["loadType"] == "dynamic":
                    file.write("bool __Stub" + service["name"] + "_register__ = StubCreatorRef.registerServiceFactory<" + service["name"] + "Stub, rpc::StubFactoryReentrantDynamicT<" + service["name"] + "Stub>>();\n\n")
                else:
                    file.write("bool __Stub" + service["name"] + "_register__ = StubCreatorRef.registerServiceFactory<" + service["name"] + "Stub, rpc::StubFactoryReentrantT<" + service["name"] + "Stub>>();\n\n")
            file.write(service["name"] + "Stub::" + service["name"] + "Stub() {\n")
            if service["loadType"] != "dynamic":
                file.write("    service_ = std::shared_ptr<" + service["name"] + "Impl>();\n")
            if service["type"] == "single":
                file.write("    type_ = rpc::StubType::SINGLE;\n")
            elif service["type"] == "multiple":
                file.write("    type_ = rpc::StubType::MULTIPLE;\n")
            elif service["type"] == "reentrant":
                file.write("    type_ = rpc::StubType::REENTRANT;\n")
            elif service["type"] == "generic":
                file.write("    type_ = rpc::StubType::GENERIC;\n")
            file.write("}\n\n")
            file.write("bool " + service["name"] +  "Stub::onAfterFork(rpc::Rpc* rpc) {\n")
            file.write("    if (service_) {\n")
            file.write("        service_->setContext(getContext());\n")
            file.write("        service_->setServiceUUID(getUUID());\n")
            file.write("        return service_->onAfterFork(rpc);\n")
            file.write("    }\n")
            file.write("    if (getEntryFunc()) {\n")
            file.write("        service_ = std::shared_ptr<" + service["name"] +">(dynamic_cast<" + service["name"] + "*>(getEntryFunc()()));\n")
            file.write("        service_->setContext(getContext());\n")
            file.write("        service_->setServiceUUID(getUUID());\n")
            file.write("        return service_->onAfterFork(rpc);\n")
            file.write("    }\n")
            file.write("    return false;\n")
            file.write("}\n\n")
            file.write("bool " + service["name"] + "Stub::onBeforeDestory(rpc::Rpc* rpc) { if (service_) { return service_->onBeforeDestory(rpc); } return true; }\n\n")
            if service["loadType"] == "dynamic":
                file.write("bool " + service["name"] + "Stub::reset(rpc::BundleEntryFunc entryFunc, rpc::Rpc* rpc) {\n")
                file.write("    if (!entryFunc && zeroref()) {\n")
                file.write("        if (service_) { service_->onBeforeDestory(rpc); }\n")
                file.write("        service_ = nullptr;\n")
                file.write("        setEntryFunc(nullptr);\n")
                file.write("        return true;\n")
                file.write("    }\n")
                file.write("    if (getStatus() != rpc::StubStatus::UPDATING) { return true; }\n")
                file.write("    if (!zeroref()) { return true; }\n")                
                file.write("    auto service = service_;\n")
                file.write("    auto oldEntryFunc = getEntryFunc();\n")
                file.write("    try {\n")
                file.write("        if (service_) {\n")
                file.write("            service_->onBeforeDestory(rpc);\n")
                file.write("        }\n")
                file.write("        service_ = nullptr;\n")
                file.write("        setEntryFunc(entryFunc);\n")
                file.write("        if (!onAfterFork(rpc)) {\n")
                file.write("            service_ = service;\n")
                file.write("            setEntryFunc(oldEntryFunc);\n")
                file.write("            return false;\n")
                file.write("        }\n")
                file.write("        service = nullptr;\n")
                file.write("    } catch (std::exception& e) {\n")
                file.write('        Logbegin << "Exception thrown when call method [' + service["name"] + 'Stub::onBeforeDestory()]:" << e.what() << Logend;\n')
                file.write('        service_ = service;\n')
                file.write("        setEntryFunc(oldEntryFunc);\n")
                file.write("        return false;\n")
                file.write("    }\n")
                file.write("    dynamic_cast<rpc::StubFactoryDynamic*>(getFactory())->unload();\n")
                file.write("    setStatus(rpc::StubStatus::RESOLVED);\n")
                file.write("    return true;\n")
                file.write("}\n\n")
            else:
                file.write("bool " + service["name"] + "Stub::reset(rpc::BundleEntryFunc, rpc::Rpc* rpc) { return true; }\n\n")
            file.write("void " + service["name"] + "Stub::tick(std::time_t ms) { if (service_) { service_->onTick(ms); } }\n\n")
            file.write("const char* " + service["name"] + "Stub::getMethodName(rpc::MethodID method) {\n")
            file.write("    switch(method) {\n")
            n = 1;
            if service["methods"] is not None:
                for method in service["methods"]:
                    file.write("        case " + str(n) + ': return "' + service["name"] + "::" + method["name"] + '";\n')
                    n += 1
            file.write('        default: return "";\n')
            file.write("    }\n")
            file.write("}\n\n")
            file.write("void " + service["name"] + "Stub::call(rpc::StubCallPtr callPtr) {\n")
            file.write("    if (!service_) {\n")
            file.write("        callPtr->notFound();\n")
            file.write("        callPtr->finish();\n")
            file.write("        return;\n")
            file.write("    }\n")
            n = 1
            if service['type'] == 'generic':
                file.write('    service_->onServiceCall(callPtr);\n')
                file.write("}\n\n")
            else:
                file.write("    switch(callPtr->getMethodID()) {\n")
                if service["methods"] is not None:
                    for method in service["methods"]:
                        file.write("        case " + str(n) +  ":\n")
                        file.write("            " + method["name"] + "(callPtr);\n")
                        file.write("            break;\n")
                        n += 1
                file.write("        default:\n")
                file.write("            callPtr->notFound();\n")
                file.write("            callPtr->finish();\n")
                file.write("            break;\n")
                file.write("    }\n")
                file.write("}\n\n")
            if (service["type"] != "generic") and (service["methods"] is not None):
                for method in service["methods"]:
                    file.write("void " + service["name"] + "Stub::" + method["name"] + "(rpc::StubCallPtr callPtr) {\n")
                    n = 1
                    for arg in method["arguments"]:
                        if arg["IdlType"] == "void":
                            break;
                        file.write("    ")
                        if arg["IdlType"] == "seq" or arg["IdlType"] == "set":
                            file.write(arg["type"] + "<" + arg["key"]["type"] + ">")
                        elif arg["IdlType"] == "dict":
                            file.write(arg["type"] + "<" + arg["key"]["type"] + "," + arg["value"]["type"] + ">")
                        elif arg["IdlType"] == "struct" or arg["IdlType"] == "string":
                            file.write(arg["type"])
                        else:
                            file.write(arg["type"])
                        file.write(" _" + str(n) + ";\n")
                        n += 1
                    file.write("    deserialize_stub_" + service["name"] + "_" + method["name"] + "(callPtr")
                    for arg in method["arguments"]:
                        if arg["IdlType"] == "void":
                            break;
                        file.write(", _" + str(arg["index"]))
                    file.write(");\n")
                    file.write("    try {\n")
                    if method["retType"]["IdlType"] != "void" and not "oneway" in method:
                        file.write("        auto ret = service_->" + method["name"] + "(callPtr")                    
                    else:
                        file.write("        service_->" + method["name"] + "(callPtr")
                    n = 1
                    for arg in method["arguments"]:
                        if arg["IdlType"] == "void":
                            break;
                        file.write(", _" + str(n))
                        n += 1
                    file.write(");\n")
                    if not "oneway" in method:
                        if method["retType"]["IdlType"] == "void":
                            file.write("        serialize_stub_" + service["name"] + "_" + method["name"] + "_retval(callPtr, getMethodName(" + str(method["index"]) + "), getServiceID(), static_cast<rpc::ErrorID>(rpc::RpcError::OK));\n")  
                        else:
                            file.write("        serialize_stub_" + service["name"] + "_" + method["name"] + "_retval(callPtr, getMethodName(" + str(method["index"]) + "), getServiceID(), static_cast<rpc::ErrorID>(rpc::RpcError::OK), ret);\n")  
                    file.write("    } catch(std::exception& e) {\n")
                    file.write('        Logbegin << "Exception thrown when call method [" << getMethodName(' + str(method["index"]) + ') << "]:" << e.what() << Logend;\n')
                    if not "oneway" in method:
                        if method["retType"]["IdlType"] == "void":
                            file.write("        serialize_stub_" + service["name"] + "_" + method["name"] + "_retval(callPtr, getMethodName(" + str(method["index"]) + "), getServiceID(), static_cast<rpc::ErrorID>(rpc::RpcError::EXCEPTION));\n")                      
                        else:                        
                            file.write("        serialize_stub_" + service["name"] + "_" + method["name"] + "_retval(callPtr, getMethodName(" + str(method["index"]) + "), getServiceID(), static_cast<rpc::ErrorID>(rpc::RpcError::EXCEPTION), ")
                            if method["retType"]["IdlType"] == "seq" or method["retType"]["IdlType"] == "set":
                                file.write("nullptr")
                            elif method["retType"]["IdlType"] == "dict":
                                file.write("nullptr")
                            elif method["retType"]["IdlType"] == "struct" or method["retType"]["IdlType"] == "string":                      
                                file.write("nullptr")
                            else:
                                file.write("0")
                            file.write(");\n")
                    file.write("    }\n")
                    file.write("    callPtr->finish();\n")
                    file.write("}\n\n")
if __name__ == "__main__":
    file = open(sys.argv[1])
    json = json.load(file)
    FileGenerator(sys.argv[1], json)
    